package app.domain.entity.attribute_converter;

import org.locationtech.jts.geom.*;
import org.locationtech.jts.geom.impl.PackedCoordinateSequenceFactory;
import org.locationtech.jts.io.WKTReader;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.io.IOException;

@Converter
public class GeometryAttributeConverter implements AttributeConverter<Geometry, String> {
    /**
     * convertToDatabaseColumn
     */
    @Override
    public String convertToDatabaseColumn(Geometry geom) {
        return geom.toString();
    }

    /**
     * convertToEntityAttribute
     */
    @Override
    public Geometry convertToEntityAttribute(String wkt) {
        Geometry geom;

        geom = null;
        try {
            geom = geomFromWkt(wkt);
        } catch (IOException ignored) {
        }
        return geom;
    }

    private static final PrecisionModel PRECISION_MODEL =
            new PrecisionModel(PrecisionModel.FLOATING);

    private static final GeometryFactory FACTORY =
            new GeometryFactory(PRECISION_MODEL, 0, PackedCoordinateSequenceFactory.DOUBLE_FACTORY);

    private static final WKTReader READER =
            new WKTReader(FACTORY);

    /**
     * geomFromWkt
     *
     * @param wkt 必须是WKT格式或EWKT格式的字符串
     * @return Geometry对象
     * @throws IOException 无法解析字符串
     */
    private static Geometry geomFromWkt(String wkt) throws IOException {
        Geometry result;

        wkt = wkt.trim();
        try {
            // no srid := 0 in JTS world
            int srid = 0;
            // break up geometry into srid and wkt
            if (wkt.startsWith("SRID=")) {
                String[] temp = wkt.split(";");
                wkt = temp[1].trim();
                srid = Integer.parseInt(temp[0].substring(5));
            }
            result = READER.read(wkt);
            setSridRecurse(result, srid);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            throw new IOException("Error parsing WKT text:" + e);
        }
    }

    /**
     * Recursively set a srid for the geometry and all sub-geometries
     * @param geom Geometry to work on
     * @param srid SRID to be set to
     */
    public static void setSridRecurse(final Geometry geom, final int srid) {
        geom.setSRID(srid);
        if (geom instanceof GeometryCollection) {
            final int n = geom.getNumGeometries();
            for (int i = 0; i < n; i++) {
                setSridRecurse(geom.getGeometryN(i), srid);
            }
        } else if (geom instanceof Polygon) {
            Polygon poly = (Polygon) geom;
            poly.getExteriorRing().setSRID(srid);
            final int n = poly.getNumInteriorRing();
            for (int j = 0; j < n; j++) {
                poly.getInteriorRingN(j).setSRID(srid);
            }
        }
    }
}
